#include "formdmxaddrsetting.h"
#include "ui_formdmxaddrsetting.h"
#include "dcsproto/proto.h"


#include <QDebug>
#include <QtEndian>
#include <QThread>
#include <QCheckBox>
#include <global.h>

FormDMXAddrSetting::FormDMXAddrSetting(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::FormDMXAddrSetting)
{
    ui->setupUi(this);
    numberkeyboard = new DialogVKB(this);
    setWindowFlags(windowFlags() | Qt::Dialog);
    setWindowModality(Qt::ApplicationModal);
    setAttribute(Qt::WA_DeleteOnClose);

    mDbopt = new DCSDbOperator();
    quint8 iface;
    if (!DCSDbOperator::getMasterParameterInterface(iface))
    {
        qDebug() << "db get interface error,set to default";
        iface = UDP_IFACE_EN_WAN;
    }

    if (iface == UDP_IFACE_EN_WAN)
    {
        mUdp = new UdpWorker(INTERFACE_WAN_NAME);
    }
    else
    {
        mUdp = new UdpWorker(INTERFACE_LAN_NAME);
    }

    mDriveBoradType = 0;

    //将所有lineedit信号都和软件盘界面显示关联
    connect(ui->lineEditStartID, SIGNAL(send_show(QString)), this, SLOT(show_numberkeyboard_ui(QString)));
    connect(ui->lineEditStartAddr, SIGNAL(send_show(QString)), this, SLOT(show_numberkeyboard_ui(QString)));
    connect(ui->lineEditLedChNum, SIGNAL(send_show(QString)), this, SLOT(show_numberkeyboard_ui(QString)));
    connect(numberkeyboard, SIGNAL(sendMessage(QString)), this, SLOT(confirmString(QString)));
    connect(mUdp, &UdpWorker::dataRecvdBytes, this, &FormDMXAddrSetting::on_dataRecved);

    qDebug() << "[FormDMXAddrSetting] \t Constructor";
}

FormDMXAddrSetting::~FormDMXAddrSetting()
{
    delete ui;
    delete mUdp;
    delete numberkeyboard;
    delete mDbopt;
    qDebug() << "[FormDMXAddrSetting] \t Destructor";
}

/**
 * @brief FormDMXAddrSetting::dmxAddrWrite
 *          分2帧发送DMX地址数据，每帧包含 512个地址 = 512*2 =1024个字节
 *          首帧协议字段为36字节，其他帧协议字段为20，故帧大小分别为1060和1044，未超过UDP payload最大大小1472
 * @param slaveId
 */
void FormDMXAddrSetting::dmxAddrWrite(unsigned short slaveId)
{
    char bigbuf[36 + 512 * 2];
    struct slave_dmx_addr_set_pdu pdu{};
    unsigned short addr;
    int length;
    int invalidPortCount = 0;
    int portChecked[8];

    //判断端口是否勾选
    memset(portChecked, 0x0, sizeof(portChecked));

    if (ui->checkBoxPort1->isChecked())
    {
        portChecked[0] = 1;
        invalidPortCount++;
    }

    if (ui->checkBoxPort2->isChecked())
    {
        portChecked[1] = 1;
        invalidPortCount++;
    }

    if (ui->checkBoxPort3->isChecked())
    {
        portChecked[2] = 1;
        invalidPortCount++;
    }

    if (ui->checkBoxPort4->isChecked())
    {
        portChecked[3] = 1;
        invalidPortCount++;
    }

    if (ui->checkBoxPort5->isChecked())
    {
        portChecked[4] = 1;
        invalidPortCount++;
    }

    if (ui->checkBoxPort6->isChecked())
    {
        portChecked[5] = 1;
        invalidPortCount++;
    }

    if (ui->checkBoxPort7->isChecked())
    {
        portChecked[6] = 1;
        invalidPortCount++;
    }

    if (ui->checkBoxPort8->isChecked())
    {
        portChecked[7] = 1;
        invalidPortCount++;
    }

    //发送勾选端口的DMX地址数据
    for (int port = 1; port <= invalidPortCount; port++)
    {
        int ledIndex = 0;
        if (port == 1)  //发送首包前半帧数据
        {
            memset(bigbuf, 0x0, sizeof(bigbuf));
            memset(&pdu, 0x0, sizeof(pdu));
            pdu.tag = SLAVE_DMX_ADDR_SET_FIX_TAG;
            pdu.pkgnum = invalidPortCount * 2;
            pdu.pkgno = port * 2 - 1;
            pdu.board = mDriveBoradType;
            pdu.chip = EN_LED_CHIP_TYPE_UCS512C;

            for (int portIndex = 0; portIndex < 8; portIndex++)
            {
                if (portChecked[portIndex])
                {
                    pdu.pkgdata.first_pkg.datalen[portIndex] = 2048;
                }
                else
                {
                    pdu.pkgdata.first_pkg.datalen[portIndex] = 0;
                }

            }

            for (ledIndex = 0; ledIndex < 512; ++ledIndex)
            {
                addr = (mStartAddr - 1) + (ledIndex * mLedColorNum);
                pdu.pkgdata.first_pkg.addrdata[ledIndex] = qToBigEndian(addr);
            }

            length = aklt_proto_encode((unsigned char *) bigbuf, TYP_SLAVE_DMX_ADDR_SET, CMD_SLAVE_DMX_ADDR_SET,
                                       slaveId,
                                       (unsigned char *) &pdu, sizeof(pdu), SLAVE_UNICAST);
            mUdp->dataSend(bigbuf, length);
        }
        else //发送非首包前半帧数据
        {
            memset(bigbuf, 0x0, sizeof(bigbuf));
            memset(&pdu, 0x0, sizeof(pdu));
            pdu.tag = SLAVE_DMX_ADDR_SET_FIX_TAG;
            pdu.pkgnum = invalidPortCount * 2;
            pdu.pkgno = port * 2 - 1;
            pdu.board = mDriveBoradType;
            pdu.chip = EN_LED_CHIP_TYPE_UCS512C;
            for (ledIndex = 0; ledIndex < 512; ++ledIndex)
            {
                addr = (mStartAddr - 1) + (ledIndex * mLedColorNum);
                pdu.pkgdata.pkg.addrdata[ledIndex] = qToBigEndian(addr);
            }

            length = aklt_proto_encode((unsigned char *) bigbuf, TYP_SLAVE_DMX_ADDR_SET, CMD_SLAVE_DMX_ADDR_SET,
                                       slaveId,
                                       (unsigned char *) &pdu, sizeof(pdu), SLAVE_UNICAST);
            mUdp->dataSend(bigbuf, length - 16);
        }

        //发送后半帧数据
        memset(bigbuf, 0x0, sizeof(bigbuf));
        memset(&pdu, 0x0, sizeof(pdu));
        pdu.tag = SLAVE_DMX_ADDR_SET_FIX_TAG;
        pdu.pkgnum = invalidPortCount * 2;
        pdu.pkgno = port * 2;
        pdu.board = mDriveBoradType;
        pdu.chip = EN_LED_CHIP_TYPE_UCS512C;
        for (; ledIndex < 1024; ++ledIndex)
        {
            addr = (mStartAddr - 1) + (ledIndex * mLedColorNum);
            pdu.pkgdata.pkg.addrdata[ledIndex - 512] = qToBigEndian(addr);
        }

        length = aklt_proto_encode((unsigned char *) bigbuf, TYP_SLAVE_DMX_ADDR_SET, CMD_SLAVE_DMX_ADDR_SET, slaveId,
                                   (unsigned char *) &pdu, sizeof(pdu), SLAVE_UNICAST);
        mUdp->dataSend(bigbuf, length - 16);
        qDebug() << "send port:" << port << "dmx addr";
    }
}

void FormDMXAddrSetting::dmxAddrWriteCheck(unsigned short slaveId)
{
    char buf[60];
    struct slave_conf_read_pdu pdu;

    memset(buf, 0x0, sizeof(buf));
    memset(&pdu, 0x0, sizeof(pdu));
    pdu.conf_id = SLAVE_CONF_DMX_RESET;

    aklt_proto_encode((unsigned char *) buf, TYP_SLAVE_CONF_READ, CMD_SLAVE_CONF_READ, slaveId,
                      (unsigned char *) &pdu, sizeof(pdu), SLAVE_UNICAST);
    mUdp->dataSend(buf, 60);
}

void FormDMXAddrSetting::on_pushButtonDMXAddrSettingReturn_clicked()
{
    this->close();
}

void FormDMXAddrSetting::show_numberkeyboard_ui(QString data)
{
    lineEdit_object = sender()->objectName();//获得调用软件盘的部件的名称
    numberkeyboard->setInputdata(data);
    numberkeyboard->show();
}

void FormDMXAddrSetting::confirmString(QString gemfield)
{
    //判断应该将信息写入哪一个输入框
    if (lineEdit_object == ui->lineEditStartID->objectName())
    {
        ui->lineEditStartID->setText(gemfield);
    }
    else if (lineEdit_object == ui->lineEditStartAddr->objectName())
    {
        ui->lineEditStartAddr->setText(gemfield);
    }
    else if (lineEdit_object == ui->lineEditLedChNum->objectName())
    {
        ui->lineEditLedChNum->setText(gemfield);
    }
}

void FormDMXAddrSetting::on_pushButtonWrite_clicked()
{
    mLedNo = ui->lineEditStartID->text().toInt();
    mLedColorNum = ui->lineEditLedChNum->text().toInt();
    mStartAddr = ui->lineEditStartAddr->text().toInt();

    qDebug() << "mLedNo:" << mLedNo << "mLedColorNum:" << mLedColorNum << "mStartAddr:" << mStartAddr;

    towInputWin = new DialogSlaveParamWrite(this);
    connect(towInputWin, SIGNAL(accepted()), this, SLOT(on_InputDialogCommit()));
    towInputWin->show();
}


/**
 * @brief FormDMXAddrSetting::on_lineEditStartID_textChanged
 *        起始灯具编号变化，自动变化起始地址
 * @param text
 */
void FormDMXAddrSetting::on_lineEditStartID_textChanged(const QString &text)
{
    int idx = text.toInt();
    int color = ui->lineEditLedChNum->text().toInt();

    if (idx > 0)
    {
        ui->lineEditStartAddr->setText(QString::number((idx - 1) * color + 1));
    }
}

void FormDMXAddrSetting::on_comboBoxBoardType_currentIndexChanged(int index)
{
    mDriveBoradType = index;
    qDebug() << "index:" << index;
}

void FormDMXAddrSetting::on_dataRecved(QByteArray &data)
{
    struct akltproto aklt;
    aklt_proto_decode(&aklt, (unsigned char *) (data.data()), data.size());

    qDebug() << "aklt.type:0x" << hex << aklt.type << "aklt.cmd:0x" << hex << aklt.cmd;
    if (aklt.type == TYP_SLAVE_CONF_ACK && aklt.cmd == CMD_SLAVE_DMX_RESET_ACK)
    {
        //分控DMX地址写入确认回复
        struct slave_conf_ack_pdu *ack = (struct slave_conf_ack_pdu *) (aklt.data);
        qDebug() << "dmx addr write check ack, " << "slave id:" << aklt.id << "finished:" << ack->finished;
    }

    delete aklt.data;
}

void FormDMXAddrSetting::on_checkBoxPortAll_stateChanged(int arg1)
{
    bool isChecked;
    qDebug() << "state:" << arg1;
    if (arg1 == Qt::Checked)
    {
        isChecked = true;
    }
    else
    {
        isChecked = false;
    }

    ui->checkBoxPort1->setChecked(isChecked);
    ui->checkBoxPort2->setChecked(isChecked);
    ui->checkBoxPort3->setChecked(isChecked);
    ui->checkBoxPort4->setChecked(isChecked);
    ui->checkBoxPort5->setChecked(isChecked);
    ui->checkBoxPort6->setChecked(isChecked);
    ui->checkBoxPort7->setChecked(isChecked);
    ui->checkBoxPort8->setChecked(isChecked);
}

void FormDMXAddrSetting::on_lineEditLedChNum_textChanged(const QString &arg1)
{
    int idx = ui->lineEditStartID->text().toInt();
    int color = arg1.toInt();

    if (idx > 0)
    {
        ui->lineEditStartAddr->setText(QString::number((idx - 1) * color + 1));
    }
}

void FormDMXAddrSetting::on_InputDialogCommit()
{
    int sid, eid;

    towInputWin->getInputValue(sid, eid);

    qDebug() << "start id:" << sid << "end id:" << eid;
    if (sid <= eid)
    {
        ui->progressBar->setMaximum(eid - sid);
        ui->progressBar->setMinimum(0);
        for (int slaveId = sid; slaveId <= eid; slaveId++)
        {
            dmxAddrWrite(slaveId);
            dmxAddrWriteCheck(slaveId);
            ui->progressBar->setValue(slaveId - sid);
        }
    }
}
